package com.dreamoo.common.threadpool.wrapper;

import cn.hutool.core.map.MapUtil;
import com.dreamoo.common.exception.BusinessException;
import com.dreamoo.common.result.ResultCode;
import com.dreamoo.common.threadlocal.BaseParameterHolder;

import java.util.Map;
import java.util.concurrent.Callable;

/**
 * @author 山顶洞人郑某
 * @className DreamooTaskWrapper.java 线程池任务包装器 （装饰者）
 * @date 2025 05 06
 */
public class DreamooTaskWrapper {

    /**
     * 获取线程局部变量
     * @return 线程局部变量
     */
    protected static Map<String,String> getThreadLocalParameter(){
        return BaseParameterHolder.getAll();
    }
    /**
     * 线程池任务包装
     *
     * @param runnable 原始Runnable
     * @return 包装后的Runnable对象 支持线程局部变量
     */
    public static Runnable wrap(Runnable runnable){
        if (runnable == null) {
            return null;
        }
        //先获取父线程的局部变量的值 这里是在父线程中执行的 所以获取的结果就是当前线程（父线程）中的值
        Map<String,String> parentParameter = getThreadLocalParameter();
        return new Runnable() {  //而这里是创建了一个Runnable对象 当这个对象在线程池中运行的时候，就相当于是一个新的线程里面执行
            @Override
            public void run() {
                Map<String, String> threadLocalParameter = getThreadLocalParameter();//先获取本线程原本的局部变量 以便在finally中恢复
                setThreadLocal(parentParameter); //将父线程的局部变量的值传入当前线程中
               try {
                   runnable.run();
               }
               finally {
                   resetThreadLocal(threadLocalParameter); //将本线程原本的局部变量的值恢复回去
               }
            }
        };
    }



    /**
     * 有返回值的任务执行
     * @param callable 原始Callable
     * @return 包装的Callable
     * @param <T> 返回值类型
     */

    public static  <T> Callable<T> wrap(Callable<T> callable){
        if (callable == null) {
            return null;
        }
        //先获取父线程的局部变量
        Map<String,String> parentParameter = getThreadLocalParameter();
        return new Callable<T>() {
            @Override
            public T call() throws Exception {
                // 获取本线程原本的局部变量的值 用于后续恢复
                Map<String, String> threadLocalParameter = getThreadLocalParameter();
                //将父线程的局部变量的值传入当前线程中
                setThreadLocal(parentParameter);
                try {
                    return callable.call();
                } finally {
                    // 将本线程原本的局部变量的值恢复回去
                    resetThreadLocal(threadLocalParameter);
                }
            }
        };
    }


    /**
     * 将本线程的局部变量的值恢复回去
     * @param threadLocalParameter 本线程原本的局部变量的值
     */
    private static void resetThreadLocal(Map<String, String> threadLocalParameter) {
        if ( MapUtil.isEmpty(threadLocalParameter) ) {
            BaseParameterHolder.remove();
        } else {
            BaseParameterHolder.setAll(threadLocalParameter);
        }
    }

    /**
     * 设置线程局部变量 将父线程的局部变量值传入当前线程中
     * @param parentParameter 父线程的局部变量的值
     */
    private static void setThreadLocal(Map<String, String> parentParameter) {
        //如果父线程局部变量是空的
        if ( MapUtil.isEmpty(parentParameter) ) {
            //清除线程局部变量
            BaseParameterHolder.remove();
            return;
        }
        //不是空的
        BaseParameterHolder.setAll(parentParameter);
    }
}
